home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / nr4.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  19KB  |  742 lines

  1. /* net/rom level 4 (transport) protocol implementation
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "timer.h"
  10. #include "ax25.h"
  11. #include "lapb.h"
  12. #include "netrom.h"
  13. #include "nr4.h"
  14. #include <ctype.h>
  15.  
  16. #undef NR4DEBUG
  17.  
  18. /* Globals: */
  19.  
  20. /* The circuit table */
  21.  
  22. struct nr4circp Nr4circuits[NR4MAXCIRC] ;
  23.  
  24. /* Various limits */
  25.  
  26. unsigned Nr4window = 4 ;        /* Max window to negotiate */
  27. unsigned Nr4retries = 10 ;        /* Max retries */
  28. unsigned Nr4qlimit = 2048 ;        /* Max bytes on receive queue */
  29.  
  30. /* Timers */
  31.  
  32. long Nr4irtt = 15000 ;            /* Initial round trip time */
  33. long Nr4acktime = 3000 ;        /* ACK delay timer */
  34. long Nr4choketime = 180000 ;    /* CHOKEd state timeout */
  35.  
  36.  
  37. /* This function is called when a net/rom layer four frame */
  38. /* is discovered inside a datagram addressed to us */
  39.  
  40. void
  41. nr4input(hdr,bp)
  42. struct nr4hdr *hdr ;
  43. struct mbuf *bp ;
  44. {
  45.     struct nr4hdr rhdr ;
  46.     struct nr4cb *cb ;
  47.     struct ax25_addr dest ;
  48.     int op ;
  49.     unsigned window ;
  50.     int acceptc ;        /* indicates that connection should be accepted */
  51.     int newconn ;        /* indicates that this is a new incoming */
  52.                         /* connection.  You'll see. */
  53.     int gotchoke ;        /* The choke flag was set in this packet */        
  54.     
  55.     op = hdr->opcode & NR4OPCODE ;    /* Mask off flags */
  56.     
  57.     if (op == NR4OPCONRQ) {            /* process connect request first */
  58.         acceptc = 1 ;
  59.         newconn = 0 ;
  60.  
  61.         /* These fields are sent regardless of success */
  62.         
  63.         rhdr.yourindex = hdr->u.conreq.myindex ;
  64.         rhdr.yourid = hdr->u.conreq.myid ;
  65.         dest = hdr->u.conreq.node ;
  66.  
  67.         /* Check to see if we have already received a connect */
  68.         /* request for this circuit. */
  69.  
  70.         if ((cb = match_n4circ((int)hdr->u.conreq.myindex, (int)hdr->u.conreq.myid,
  71.                                   &hdr->u.conreq.user, &hdr->u.conreq.node))
  72.              == NULLNR4CB) {    /* No existing circuit if NULL */
  73.  
  74.             /* Try to get a new circuit */
  75.  
  76.             if ((cb = new_n4circ()) == NULLNR4CB) {
  77.                 acceptc = 0 ;
  78.             } else {
  79.             
  80.                 /* Window is set to min of the offered and local windows */
  81.                 
  82.                 window = hdr->u.conreq.window > Nr4window ?
  83.                          Nr4window : hdr->u.conreq.window ;
  84.  
  85.                 if (init_nr4window(cb, window) == -1) {
  86.                     free_n4circ(cb) ;
  87.                     acceptc = 0 ;
  88.                 } else {
  89.                     /* Set up control block */
  90.                     cb->yournum = hdr->u.conreq.myindex ;
  91.                     cb->yourid = hdr->u.conreq.myid ;
  92.                     cb->user = hdr->u.conreq.user ;
  93.                     cb->node = hdr->u.conreq.node ;
  94.                     cb->luser = mycall ;/* we are local user on incomings */
  95.                     cb->srtt = Nr4irtt ;/* Default round trip time */
  96.                     nr4defaults(cb) ;    /* set up timers, window pointers */
  97.                     cb->s_upcall = nr4_incom ;
  98.                     cb->state = NR4STDISC ;
  99.                     newconn = 1 ;
  100.                 } /* End if window successfully allocated */
  101.                 
  102.             }    /* End if new circuit available */
  103.             
  104.          } /* End if no existing circuit matching parameters */
  105.          
  106.         /* Now set up response */
  107.  
  108.         if (!acceptc) {
  109.             rhdr.opcode = NR4OPCONAK | NR4CHOKE ;/* choke means reject */
  110.             rhdr.u.conack.myindex = 0 ;
  111.             rhdr.u.conack.myid = 0 ;
  112.             rhdr.u.conack.window = 0 ;
  113.         } else {
  114.             rhdr.opcode = NR4OPCONAK ;
  115.             rhdr.u.conack.myindex = cb->mynum ;
  116.             rhdr.u.conack.myid = cb->myid ;
  117.             rhdr.u.conack.window = cb->window ;
  118.         }
  119.         nr4sframe(&dest, &rhdr, NULLBUF) ;
  120.  
  121.         /* Why, you ask, do we wait until now for the state change */
  122.         /* upcall?  Well, it's like this:  if the state change triggers */
  123.         /* something like the mailbox to send its banner, the banner */
  124.         /* would have gone out *before* the conn ack if we'd done this */
  125.         /* in the code above.  This is what happens when you don't plan */
  126.         /* too well.  Learn from my mistakes :-) */
  127.         
  128.         if (newconn)
  129.             nr4state(cb, NR4STCON) ;/* connected (no 3-way handshake) */
  130.             
  131.         free_p(bp) ;
  132.         return ;
  133.     } /* end connect request code */
  134.  
  135.     /* validate circuit number */
  136.  
  137.     if ((cb = get_n4circ((int)hdr->yourindex, (int)hdr->yourid)) == NULLNR4CB) {
  138.         free_p(bp) ;
  139.         return ;
  140.     }
  141.  
  142.     /* Check for choke flag */
  143.  
  144.     if (hdr->opcode & NR4CHOKE)
  145.         gotchoke = 1 ;
  146.     else
  147.         gotchoke = 0 ;
  148.     
  149.     /* Here's where the interesting stuff gets done */
  150.  
  151.     switch (cb->state) {
  152.       case NR4STCPEND:
  153.         switch (op) {
  154.           case NR4OPCONAK:
  155.             stop_timer(&cb->tcd) ;
  156.             if (gotchoke) {                    /* connect rejected */
  157.                 cb->dreason = NR4RREFUSED ;
  158.                 nr4state(cb, NR4STDISC) ;
  159.                 break ;
  160.             }
  161.             cb->yournum = hdr->u.conack.myindex ;
  162.             cb->yourid = hdr->u.conack.myid ;
  163.             window = hdr->u.conack.window > Nr4window ?
  164.                      Nr4window : hdr->u.conack.window ;
  165.  
  166.             if (init_nr4window(cb, window) == -1) {
  167.                 cb->dreason = NR4RRESET ;
  168.                 nr4state(cb, NR4STDISC) ;
  169.             } else {
  170.                 nr4defaults(cb) ;    /* set up timers, window pointers */
  171.                 
  172.                 if (cb->cdtries == 1)             /* No retries */
  173.                     cb->srtt = cb->tcd.count * MSPTICK ;/* Use measured rtt */
  174.                 else
  175.                     cb->srtt = Nr4irtt ;        /* else use default */
  176.                     
  177.                 nr4state(cb, NR4STCON) ;
  178.                 nr4output(cb) ;        /* start sending anything on the txq */
  179.             }
  180.             break ;
  181.  
  182.           default:        /* We can't respond to anything else without */
  183.                           /* Their ID and index */
  184.               free_p(bp) ;
  185.             return ;
  186.         }
  187.         break ;
  188.         
  189.       case NR4STCON:
  190.         switch (op) {
  191.           case NR4OPDISRQ:
  192.             /* format reply packet */
  193.             rhdr.opcode = NR4OPDISAK ;
  194.             rhdr.yourindex = cb->yournum ;
  195.             rhdr.yourid = cb->yourid ;
  196.     
  197.             nr4sframe(&cb->node, &rhdr, NULLBUF) ;
  198.  
  199.             cb->dreason = NR4RREMOTE ;
  200.             nr4state(cb, NR4STDISC) ;
  201.  
  202.             break ;
  203.             
  204.           case NR4OPINFO:
  205.             /* Do receive frame processing */
  206.               nr4rframe(cb, hdr->u.info.txseq, bp) ;
  207.  
  208.             /* Reset the choke flag if no longer choked.  Processing */
  209.             /* the ACK will kick things off again. */
  210.             
  211.             if (cb->choked && !gotchoke) {
  212.                 stop_timer(&cb->tchoke) ;
  213.                 cb->choked = 0 ;
  214.             }
  215.                 
  216.             /* We delay processing the receive sequence number until */
  217.             /* now, because the ACK might pull more off the txq and send */
  218.             /* it, and we want the implied ACK in those frames to be right */
  219.  
  220.             /* Only process NAKs if the choke flag is off.  It appears */
  221.             /* that NAKs should never be sent with choke on, by the way, */
  222.             /* but you never know, considering that there is no official */
  223.             /* standard for this protocol */
  224.             
  225.             if (hdr->opcode & NR4NAK && !gotchoke)
  226.                 nr4gotnak(cb, hdr->u.info.rxseq) ;
  227.  
  228.             /* We always do ACK processing, too, since the NAK of one */
  229.             /* packet may be the implied ACK of another.  The gotchoke */
  230.             /* flag is used to prevent sending any new frames, since */
  231.             /* we are just going to purge them next anyway if this is */
  232.             /* the first time we've seen the choke flag.  If we are */
  233.             /* already choked, this call will return immediately. */
  234.             
  235.             nr4ackours(cb, hdr->u.info.rxseq, gotchoke) ;
  236.  
  237.             /* If we haven't seen the choke flag before, purge the */
  238.             /* send window and set the timer and the flag. */
  239.             
  240.             if (!cb->choked && gotchoke)
  241.                 nr4choke(cb) ;
  242.             
  243.             break ;
  244.  
  245.           case NR4OPACK:
  246.             if (cb->choked && !gotchoke) {    /* clear choke if appropriate */
  247.                 stop_timer(&cb->tchoke) ;
  248.                 cb->choked = 0 ;
  249.             }
  250.                 
  251.               if (hdr->opcode & NR4NAK && !gotchoke)
  252.                 nr4gotnak(cb, hdr->u.ack.rxseq) ;    /* process NAKs */
  253.                 
  254.               nr4ackours(cb, hdr->u.ack.rxseq, gotchoke) ; /* and ACKs */
  255.  
  256.             if (!cb->choked && gotchoke)    /* First choke seen */
  257.                 nr4choke(cb) ;                /* Set choke status */
  258.  
  259.             break ;
  260.         }
  261.         break ;
  262.         
  263.       case NR4STDPEND:
  264.         switch (op) {
  265.           case NR4OPDISAK:
  266.               cb->dreason = NR4RNORMAL ;
  267.             nr4state(cb, NR4STDISC) ;
  268.             break ;
  269.             
  270.           case NR4OPINFO:
  271.             /* We can still do receive frame processing until */
  272.             /* the disconnect acknowledge arrives, but we won't */
  273.             /* bother to process ACKs, since we've flushed our */
  274.             /* transmit buffers and queue already. */
  275.             
  276.               nr4rframe(cb, hdr->u.info.txseq, bp) ;
  277.  
  278.             break ;
  279.         }
  280.     
  281.     }    /* End switch(state) */
  282.  
  283. }
  284.  
  285.  
  286. /* Send a net/rom layer 4 frame.  bp should be NULLBUF unless the frame
  287.  * type is info.
  288.  */
  289.  
  290. void
  291. nr4sframe(dest, hdr, bp)
  292. struct ax25_addr *dest ;
  293. struct nr4hdr *hdr ;
  294. struct mbuf *bp ;
  295. {
  296.     void nr3output() ;
  297.     struct mbuf *n4b ;
  298.  
  299.     if ((n4b = htonnr4(hdr)) == NULLBUF) {
  300.         free_p(bp) ;
  301.         return ;
  302.     } else {
  303.         append(&n4b, bp) ;
  304.         nr3output(dest, n4b) ;
  305.     }
  306. }
  307.  
  308. /* Receive frame processing */
  309.  
  310. void
  311. nr4rframe(cb, rxseq, bp)
  312. struct nr4cb *cb ;
  313. unsigned rxseq ;
  314. struct mbuf *bp ;
  315. {
  316.     struct nr4hdr rhdr ;
  317.     unsigned window = cb->window ;
  318.     unsigned rxbuf = rxseq % window ;
  319.     unsigned newdata = 0 ;        /* whether to upcall */
  320.  
  321. #ifdef NR4DEBUG
  322.     printf("Processing received info\n") ;
  323. #endif
  324.  
  325.     /* If we're choked, just reset the ACK timer to blast out */
  326.     /* another CHOKE indication after the ackdelay */
  327.  
  328.     if (cb->qfull) {
  329.         start_timer(&cb->tack) ;
  330.         return ;
  331.     }
  332.     
  333.     /* If the frame is out of sequence, NAK it if we haven't */
  334.     /* already done so */
  335.     
  336.       if (rxseq != cb->rxpected && !cb->naksent) {
  337. #ifdef NR4DEBUG
  338.         printf("Frame out of sequence -- expected %u, got %u.\n",
  339.                cb->rxpected, rxseq) ;
  340. #endif                
  341.         rhdr.opcode = NR4OPACK | NR4NAK ;
  342.         rhdr.yourindex = cb->yournum ;
  343.         rhdr.yourid = cb->yourid ;
  344.         rhdr.u.ack.rxseq = cb->rxpected ;
  345.         nr4sframe(&cb->node, &rhdr, NULLBUF) ;
  346.         
  347.         /* Now make sure we don't send any more of these until */
  348.         /* we see some good data.  Otherwise full window retransmissions */
  349.         /* would result in a flurry of NAKs */
  350.         
  351.         cb->naksent = 1 ;
  352.     }
  353.             
  354.     /* If this is a new frame, within the window, buffer it, */
  355.     /* then see what we can deliver */
  356.             
  357.     if (nr4between(cb->rxpected,rxseq,cb->rxpastwin)
  358.         && !cb->rxbufs[rxbuf].occupied) {
  359. #ifdef NR4DEBUG
  360.         printf("Frame within window\n") ;
  361. #endif
  362.         cb->rxbufs[rxbuf].occupied = 1 ;
  363.         cb->rxbufs[rxbuf].data = bp ;
  364.                 
  365.         for (rxbuf = cb->rxpected % window ; cb->rxbufs[rxbuf].occupied ; 
  366.              rxbuf = cb->rxpected % window) {
  367. #ifdef NR4DEBUG
  368.             printf("Removing frame from buffer %d\n", rxbuf) ;
  369. #endif
  370.             newdata = 1 ;
  371.             cb->rxbufs[rxbuf].occupied = 0 ;
  372.             append(&cb->rxq,cb->rxbufs[rxbuf].data) ;
  373.             cb->rxbufs[rxbuf].data = NULLBUF ;
  374.             cb->rxpected = (cb->rxpected + 1) & NR4SEQMASK ;
  375.             cb->rxpastwin = (cb->rxpastwin + 1) & NR4SEQMASK ;
  376.         }
  377.         if (newdata) {
  378.             cb->naksent = 0 ;    /* OK to send NAKs again */
  379.             if (cb->r_upcall != NULLVFP)
  380.                 (*cb->r_upcall)(cb,len_mbuf(cb->rxq)) ;
  381.  
  382.             /* Now that our upcall has had a shot at the queue, */
  383.             /* see if it's past the queue length limit.  If so, */
  384.             /* go into choked mode (i.e. flow controlled). */
  385.  
  386.             if (len_mbuf(cb->rxq) > Nr4qlimit) {
  387.                 cb->qfull = 1 ;
  388.                 nr4ackit((char *)cb) ;    /* Tell `em right away */
  389.             } else
  390.                 start_timer(&cb->tack) ;
  391.         }
  392.     } else     /* It's out of the window or we've seen it already */
  393.         free_p(bp) ;
  394. }
  395.  
  396.  
  397. /* Send the transmit buffer whose sequence number is seq */
  398.  
  399. void
  400. nr4sbuf(cb, seq)
  401. struct nr4cb *cb ;
  402. unsigned seq ;
  403. {
  404.     struct nr4hdr hdr ;
  405.     struct mbuf *bufbp, *bp ;
  406.     unsigned bufnum = seq % cb->window ;
  407.     struct timer *t ;
  408.     
  409.     /* sanity check */
  410.  
  411.     if (bufnum >= cb->window) {
  412. #ifdef NRDEBUG
  413.         printf("sbuf: buffer number %u beyond window\n",bufnum) ;
  414. #endif
  415.         return ;
  416.     }
  417.  
  418.     /* Stop the ACK timer, since our sending of the frame is */
  419.     /* an implied ACK. */
  420.  
  421.     stop_timer(&cb->tack) ;
  422.     
  423.     /* Duplicate the mbuf, since we have to keep it around */
  424.     /* until it is acknowledged */
  425.     
  426.     bufbp = cb->txbufs[bufnum].data ;
  427.  
  428.     /* Notice that we use copy_p instead of dup_p.  This is because */
  429.     /* a frame can still be sitting on the AX.25 send queue when it */
  430.     /* get acknowledged, and we don't want to deallocate its data */
  431.     /* before it gets sent! */
  432.     
  433.     if ((bp = copy_p(bufbp, len_mbuf(bufbp))) == NULLBUF) {
  434.         free_mbuf(bp) ;
  435.         return ;
  436.     }
  437.  
  438.     /* Prepare the header */
  439.     if (cb->qfull)                /* are we choked? */
  440.         hdr.opcode = NR4OPINFO | NR4CHOKE ;
  441.     else
  442.         hdr.opcode = NR4OPINFO ;
  443.     hdr.yourindex = cb->yournum ;
  444.     hdr.yourid = cb->yourid ;
  445.     hdr.u.info.txseq = (unsigned char)(seq & NR4SEQMASK) ;
  446.     hdr.u.info.rxseq = cb->rxpected ;
  447.     
  448.     /* Send the frame, then set and start the timer */
  449.  
  450.     nr4sframe(&cb->node, &hdr, bp) ;
  451.  
  452.     t = &cb->txbufs[bufnum].tretry ;
  453.     t->start = (1 << cb->blevel) *
  454.                (2 * cb->mdev + cb->srtt + MSPTICK) / MSPTICK ;
  455.     start_timer(t) ;
  456.  
  457.     return ;
  458. }
  459.  
  460. /* Check to see if any of our frames have been ACKed */
  461.  
  462. void
  463. nr4ackours(cb, seq, gotchoke)
  464. struct nr4cb *cb ;
  465. unsigned seq ;
  466. int gotchoke ;    /* The choke flag is set in the received frame */
  467. {
  468.     unsigned txbuf ;
  469.     struct timer *t ;
  470.     
  471.     /* If we are choked, there is nothing in the send window */
  472.     /* by definition, so we can just return. */
  473.     
  474.     if (cb->choked)
  475.         return ;
  476.         
  477.     /* Adjust seq to point to the frame being ACK'd, not the one */
  478.     /* beyond it, which is how it arrives. */
  479.  
  480.     seq = (seq - 1) & NR4SEQMASK ;
  481.  
  482.     /* Free up all the ack'd frames, and adjust the round trip */
  483.     /* timing stuff */
  484.     
  485.     while (nr4between(cb->ackxpected, seq, cb->nextosend)) {
  486. #ifdef NR4DEBUG
  487.         printf("Sequence # %u acknowledged\n", seq) ;
  488. #endif
  489.         cb->nbuffered-- ;
  490.         txbuf = cb->ackxpected % cb->window ;
  491.         stop_timer(&cb->txbufs[txbuf].tretry) ;
  492.         free_mbuf(cb->txbufs[txbuf].data) ;
  493.         cb->txbufs[txbuf].data = NULLBUF ;
  494.         cb->ackxpected = (cb->ackxpected + 1) & NR4SEQMASK ;
  495.  
  496.         /* Round trip time estimation, cribbed from TCP */
  497.  
  498.         if (cb->txbufs[txbuf].retries == 0) {    /* We only sent this one once */
  499.             int32 rtt ;
  500.             int32 abserr ;
  501.  
  502.             t = &cb->txbufs[txbuf].tretry ;
  503.             rtt = (t->start - t->count) * MSPTICK ;    /* get our rtt in msec */
  504.             abserr = (rtt > cb->srtt) ? rtt - cb->srtt : cb->srtt - rtt ;
  505.             cb->srtt = (cb->srtt * 7 + rtt) >> 3 ;
  506.             cb->mdev = (cb->mdev * 3 + abserr) >> 2 ;
  507.  
  508.             /* Reset the backoff level */
  509.  
  510.             cb->blevel = 0 ;
  511.         } 
  512.     }
  513.  
  514.     /* Now we recalculate tmax, the maximum number of retries for */
  515.     /* any frame in the window.  tmax is used as a baseline to */
  516.     /* determine when the window has reached a new high in retries. */
  517.     /* We don't want to increment blevel for every frame that times */
  518.     /* out, since that would lead to us backing off too fast when */
  519.     /* all the frame timers expired at around the same time. */
  520.  
  521.     cb->txmax = 0 ;
  522.     
  523.     for (seq = cb->ackxpected ;
  524.          nr4between(cb->ackxpected, seq, cb->nextosend) ;
  525.          seq = (seq + 1) & NR4SEQMASK)
  526.         if (cb->txbufs[seq % cb->window].retries > cb->txmax)
  527.             cb->txmax = cb->txbufs[seq % cb->window].retries ;
  528.  
  529.     /* This is kind of a hack.  This function is called under */
  530.     /* three different conditions:  either we are choked, in */
  531.     /* which case we return immediately, or we are not choked, */
  532.     /* in which case we proceed normally to keep the send */
  533.     /* window full, or we have seen the choke flag for the first */
  534.     /* time.  In the last case, gotchoke is true while cb->choked */
  535.     /* is false.  We want to process any acknowledgments of existing */
  536.     /* frames in the send window before we purge it, while at the */
  537.     /* same time we don't want to take anything else off the txq */
  538.     /* or send it out.  So, in the third case we listed, we return */
  539.     /* now since we've processed the ACK. */
  540.     
  541.     if (gotchoke)
  542.         return ;
  543.         
  544.     nr4output(cb) ;            /* yank stuff off txq and send it */
  545.  
  546.     /* At this point, either the send window is full, or */
  547.     /* nr4output() didn't find enough on the txq to fill it. */
  548.     /* If the window is not full, then the txq must be empty, */
  549.     /* and we'll make a tx upcall */
  550.     
  551.     if (cb->nbuffered < cb->window)    
  552.         if (cb->t_upcall != NULLVFP)
  553.             (*cb->t_upcall)(cb, (cb->window - cb->nbuffered) * NR4MAXINFO) ;
  554.  
  555. }
  556.  
  557.  
  558. /* If the send window is open and there are frames on the txq,
  559.  * move as many as possible to the transmit buffers and send them.
  560.  * Return the number of frames sent.
  561.  */
  562.  
  563. int
  564. nr4output(cb)
  565. struct nr4cb *cb ;
  566. {
  567.     int numq, i ;
  568.     struct mbuf *bp ;
  569.     struct nr4txbuf *tp ;
  570.  
  571.     /* Are we in the proper state? */
  572.  
  573.     if (cb->state != NR4STCON || cb->choked)
  574.         return 0 ;                /* No sending if not connected */
  575.                                 /* or if choked */
  576.         
  577.     /* See if the window is open */
  578.     
  579.     if (cb->nbuffered >= cb->window)
  580.         return 0 ;
  581.  
  582.     numq = len_q(cb->txq) ;
  583.     
  584. #ifdef NR4DEBUG
  585.     printf("nr4output: %d packets on txq\n", numq) ;
  586. #endif
  587.     
  588.     for (i = 0 ; i < numq ; i++) {
  589.  
  590.         bp = dequeue(&cb->txq) ;
  591.  
  592. #ifdef NR4DEBUG
  593.         if (len_mbuf(bp) > NR4MAXINFO) {    /* should be checked higher up */
  594.             printf("Upper layers queued too big a buffer\n") ;
  595.             continue ;
  596.         }
  597. #endif
  598.         /* Set up and send buffer */
  599.         
  600.         tp = &cb->txbufs[cb->nextosend % cb->window] ;
  601.         tp->retries = 0 ;
  602.         tp->data = bp ;
  603.         nr4sbuf(cb, cb->nextosend) ;
  604.  
  605.         /* Update window and buffered count */
  606.  
  607.         cb->nextosend = (cb->nextosend + 1) & NR4SEQMASK ;
  608.         if (++cb->nbuffered >= cb->window)
  609.             break ;
  610.     }
  611.     return i ;        
  612. }
  613.  
  614. void
  615. nr4state(cb, newstate)
  616. struct nr4cb *cb ;
  617. int newstate ;
  618. {
  619.     int i ;
  620.     int oldstate = cb->state ;
  621.     
  622.     cb->state = newstate ;
  623.  
  624.     switch (cb->state) {
  625.       case NR4STDPEND:
  626.           stop_timer(&cb->tchoke);
  627.  
  628.         /* When we request a disconnect, we lose the contents of */
  629.         /* our transmit queue and buffers, but we retain our ability */
  630.         /* to receive any packets in transit until a disconnect */
  631.         /* acknowledge arrives */
  632.         
  633.         free_q(&cb->txq) ;
  634.         
  635.         for (i = 0 ; i < cb->window ; i++) {
  636.             free_mbuf(cb->txbufs[i].data) ;
  637.             cb->txbufs[i].data = NULLBUF ;
  638.             stop_timer(&cb->txbufs[i].tretry) ;
  639.         }
  640.         
  641.         /* Tidy up stats: roll the top window pointer back */
  642.         /* and reset nbuffered to reflect this.  Not really */
  643.         /* necessary, but leads to a bit more truth telling */
  644.         /* in the status displays. */
  645.  
  646.         cb->nextosend = cb->ackxpected ;
  647.         cb->nbuffered = 0 ;
  648.  
  649.         break ;
  650.         
  651.       case NR4STDISC:
  652.         stop_timer(&cb->tchoke) ;
  653.         stop_timer(&cb->tack) ;
  654.         stop_timer(&cb->tcd) ;
  655.  
  656.         /* We don't clear the rxq, since the state change upcall */
  657.         /* may pull something off of it at the last minute. */
  658.         
  659.         free_q(&cb->txq) ;
  660.  
  661.         /* The following loop will only be executed if the */
  662.         /* window was set, since when the control block is */
  663.         /* calloc'd the window field gets a 0 in it.  This */
  664.         /* protects us from dereferencing an unallocated */
  665.         /* window buffer pointer */
  666.         
  667.         for (i = 0 ; i < cb->window ; i++) {
  668.             free_mbuf(cb->rxbufs[i].data) ;
  669.             cb->rxbufs[i].data = NULLBUF ;
  670.             free_mbuf(cb->txbufs[i].data) ;
  671.             cb->txbufs[i].data = NULLBUF ;
  672.             stop_timer(&cb->txbufs[i].tretry) ;
  673.         }
  674.             
  675.         break ;
  676.     }
  677.  
  678.     if (oldstate != newstate && cb->s_upcall != NULLVFP)
  679.         (*cb->s_upcall)(cb, oldstate, newstate) ;
  680.  
  681.     /* We take responsibility for deleting the circuit */
  682.     /* descriptor.  Don't do this anywhere else! */
  683.     
  684.     if (newstate == NR4STDISC)
  685.         free_n4circ(cb) ;
  686.     
  687. }
  688.  
  689. /* Process NAKs.  seq indicates the next frame expected by the
  690.  * NAK'ing station.
  691.  */
  692.  
  693. void
  694. nr4gotnak(cb, seq)
  695. struct nr4cb *cb ;
  696. unsigned seq ;
  697. {
  698.     if (nr4between(cb->ackxpected, seq, cb->nextosend))
  699.         nr4sbuf(cb, seq) ;
  700. }
  701.  
  702.  
  703. /* This is called when we first get a CHOKE indication from the
  704.  * remote.  It purges the send window and sets the choke timer.
  705.  */
  706.  
  707. void
  708. nr4choke(cb)
  709. struct nr4cb *cb ;
  710. {
  711.     unsigned seq ;
  712.     struct mbuf *q, *bp ;
  713.     struct nr4txbuf *t ;
  714.  
  715.     q = cb->txq ;
  716.  
  717.     /* We purge the send window, returning the buffers to the */
  718.     /* txq in the proper order. */
  719.  
  720.     for (seq = (cb->nextosend - 1) & NR4SEQMASK ;
  721.          nr4between(cb->ackxpected, seq, cb->nextosend) ;
  722.          seq = (seq - 1) & NR4SEQMASK) {
  723.  
  724.         t = &cb->txbufs[seq % cb->window] ;
  725.         stop_timer(&t->tretry) ;
  726.         bp = t->data ;
  727.         t->data = NULLBUF ;
  728.         enqueue(&bp, q) ;    /* prepend this packet to the queue */
  729.         q = bp ;
  730.      }
  731.  
  732.     cb->nextosend = cb->ackxpected ;    /* close the window */
  733.     cb->nbuffered = 0 ;                    /* nothing in the window */
  734.     cb->txq = q ;            /* Replace the txq with the one that has */
  735.                             /* the purged packets prepended */
  736.     cb->choked = 1 ;        /* Set the choked flag */
  737.  
  738.     start_timer(&cb->tchoke) ;
  739.     
  740. }
  741.  
  742.